#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define NUM 1024
#define OP_NUM 64
char lineCommand[NUM];   //接收命令
char *op[OP_NUM];       //指针数组，存放拆分命令后的各字符串的指针
int lastCode=0;
int lastSignal=0;


int main()
{
    while(1)
    {
        printf("[用户名@主机名 当前路径]$ ");
        fflush(stdout);
    
        //获取用户输入
        char* s=fgets(lineCommand, sizeof(lineCommand)-1, stdin);
        assert(s != NULL);
        (void)s;
        //把我们在命令行输入的\n删掉
        lineCommand[strlen(lineCommand)-1] = 0;
    
        //拆分命令
        op[0]=strtok(lineCommand, " ");
        int i=1;
        //如果要执行ls，为其自动添加--color=auto选项
        if(op[0]!= NULL && strcmp(op[0],"ls")==0)
        {
            op[i++] = (char*)"--color=auto";
        }
        while(op[i++]=strtok(NULL, " "));
        
        //如果输入的是cd命令，即改变当前进程的工作目录，创建子进程，则改变了子进程的工作目录，子进程执行完，就结束了，无法改变父进程的
        //故不需要创建子进程，而是让shell执行，才能改变父进程的
        //这种不需要创建子进程，让shell自己执行对应的命令  这种叫做内置/内建命令
        if(op[0]!=NULL && strcmp(op[0],"cd")==0)
        {
            if(op[1] == NULL)   //cd  默认到当前用户的目录
            {
                chdir("/home/zwg");
            }
            else 
            {
                chdir(op[1]);
            }
            //shell执行完后，目录已经改变了，已经达到了我们输入cd  的目的，不需要再创建子进程了，直接输入下一条命令
            continue;
        }
        
        //echo
        if(op[0]!=NULL && strcmp(op[0],"echo")==0)
        {
            //经测试，只输入echo 会打印换行
            if(op[1]==NULL)
            {
                printf("\n");
            }
            else if(strcmp(op[1],"$?")==0)      //获取最近一次进程的退出码，这里又添加了信号
            {
                printf("%d, %d\n",lastCode, lastSignal);
            }
            else      //否则就输出我们输入的字符
            {
                printf("%s\n", op[1]);
            }

            continue;
        }



        //执行命令
        int id=fork();
        assert(id != -1);

        if(id==0)
        {
            execvp(op[0], op);
            exit(6);                                                                                                                                                     
        }
        int status=0;
        pid_t ret=waitpid(id, &status, 0);
        assert(ret != -1);
        lastCode = (status>>8) & 0xff;
        lastSignal = status & 0x7f;
    }

    return 0;
}
